#pragma once

#include<iostream>
#include<string>
#include<fcntl.h>
#include<sys/socket.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include"Log.hpp"

using namespace LogMudule;

const int SOCKFD_DEFAULT = -1;
const int LISTEN_BLOCK_DEFAULT = 1024;

class Socket
{
public:
    Socket() 
    :_sockfd(SOCKFD_DEFAULT)
    {}

    Socket(int sockfd)
    :_sockfd(sockfd)
    {}

    ~Socket()
    {
        Close();
    }

    //创建套接字
    bool Create()
    {
        _sockfd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
        if(_sockfd < 0)
        {
            LOG(LogLevel::ERROR) << "create sockfd errof ...";
            return false;
        }
        return true;
    }

    //绑定窗口
    bool Bind(const std::string& ip, uint16_t port)
    {
        struct sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(port);
        addr.sin_addr.s_addr = inet_addr(ip.c_str());
        socklen_t len = sizeof(addr);

        int n = bind(_sockfd,(struct sockaddr*)&addr,len);
        if(n < 0)
        {
            LOG(LogLevel::ERROR)<< "bind error ...";
            return false;
        }

        return true;
    }

    //设置为监听状态
    bool Listen(int block = LISTEN_BLOCK_DEFAULT)
    {
        int n = listen(_sockfd,block);
        if(n < 0)
        {
            LOG(LogLevel::ERROR) <<"listen erron...";
            return false;
        }

        return true;
    }

    //连接服务端
    bool Connect(const std::string& ip, uint16_t port)
    {
        struct sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(port);
        addr.sin_addr.s_addr = inet_addr(ip.c_str());
        socklen_t len = sizeof(addr);

        int n = connect(_sockfd,(struct sockaddr*)&addr,len);
        if(n < 0)
        {
            LOG(LogLevel::ERROR)<< "connect error ...";
            return false;
        }

        return true;
    }

    //获取新连接
    int Accept()
    {
        int new_sockfd = accept(_sockfd,nullptr,nullptr);
        if(new_sockfd < 0)
        {
            LOG(LogLevel::ERROR) << "accept error ...";
            return -1;
        }

        return new_sockfd;
    }

    //读取数据
    ssize_t Recv(void* buf, size_t len ,int flag = 0)
    {
        ssize_t size = recv(_sockfd,buf,len,flag);
        if(size <= 0)
        {
            if(errno == EAGAIN || errno == EINTR)
            {
                return 0;
            }
            LOG(LogLevel::ERROR) <<"recv error ...: " << size;
            return -1;
        }
        else if(size == 0)
        {
            //关闭连接
            return -1;
        }

        return size;
    }

    //非阻塞读取数据
    ssize_t NotBlockRecv(void* buf, size_t len)
    {
        return Recv(buf,len,MSG_DONTWAIT);
    }

    //写数据
    ssize_t Send(const void *buf, size_t len,int flag = 0)
    {
        ssize_t size = send(_sockfd,buf,len,flag);
        if(size <= 0)
        {
            if(errno == EAGAIN || errno == EINTR)
            {
                return 0;
            }
            LOG(LogLevel::ERROR) <<"send error ...";
            return -1;
        }

        return size;
    }

    //非阻塞写数据
    ssize_t NotBlockSend(const void *buf,  size_t len)
    {
        return Send(buf,len,MSG_DONTWAIT);
    }

    //设置地址重用
    void ReusingAddr()
    {
        int optval = 1;
        int n = setsockopt(_sockfd,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(optval));
        if(n < 0)
        {
            LOG(LogLevel::ERROR) <<"setsockopt addr  error ...";
        }

        optval = 1;
        n = setsockopt(_sockfd,SOL_SOCKET,SO_REUSEPORT,&optval,sizeof(optval));
        if(n < 0)
        {
            LOG(LogLevel::ERROR) <<"setsockopt port  error ...";
        }
    }

    //设置为套接字非阻塞
    void SockBlock()
    {
        int flag = fcntl(_sockfd,F_GETFL);
        fcntl(_sockfd,F_SETFL,flag | O_NONBLOCK);
    }

    //创建服务端套接字
    bool CreateServer(const std::string& ip, uint16_t port,bool flag = false)
    {
        if(Create() == false) return false;
        ReusingAddr();

        if(Bind(ip,port) == false) return false;
        if(Listen() == false) return false;

        if(flag)
        {
            SockBlock();
        }

        return true;
    }

    //创建客户端套接字
    bool CreateClient(const std::string& ip, uint16_t port,bool flag = false)
    {
        if(Create() == false) return false;
        if(Connect(ip,port) == false) return false;

        return true;
    }

    //关闭连接
    void Close()
    {
        close(_sockfd);
    }

    //获取sockfd
    int Fd()
    {
        return _sockfd;
    }

private:
    int _sockfd;
};